package com.graduate.examapp.service

import android.app.*
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkInfo
import android.os.Build
import android.os.IBinder
import android.util.Log
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.graduate.examapp.entity.ExamTask
import com.graduate.examapp.view.activity.AlarmActivity
import com.graduate.examapp.view.activity.LoginActivity
import info.mqtt.android.service.Ack
import info.mqtt.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import java.lang.reflect.Type
import java.time.LocalDate
import java.util.Timer
import java.util.TimerTask

/**
 * https://www.cnblogs.com/emqx/p/13082956.html
 * https://blog.csdn.net/weixin_42602900/article/details/128677216
 */
class MQTTService: Service() {
    private val gson = GsonBuilder().registerTypeAdapter(LocalDate::class.java, object :
        JsonDeserializer<LocalDate> {
        override fun deserialize(
            json: JsonElement?,
            typeOfT: Type?,
            context: JsonDeserializationContext?
        ): LocalDate {
            //日当前日期
            var localDate = LocalDate.now()
            json?.let {
                val asString = it.asString
                localDate = LocalDate.parse(asString)
            }
            return localDate
        }
    }).create()
    private var count: Int = 0

    private var client: MqttAndroidClient? = null
    private var conOpt: MqttConnectOptions? = null

    private val host: String = "tcp://192.168.118.97:1883";   //服务器地址
    private val userName = "admin"  //账号
    private val passWord = " c200105522."   //密码
    private val addTopic = "exam_add_"   //频道名前缀
    private val cancelTopic = "exam_cancel_"
    private var clientId: String? = null   //客户端ID

    var userNotice: UserNotice? = null

    private val networkCallback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            super.onAvailable(network)
            doClientConnection()
        }

        override fun onLost(network: Network) {
            Log.d("MQTTService", "网络丢失，MQTT连接中断")
            //client?.disconnect()
            super.onLost(network)
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // If the notification supports a direct reply action, use
        // PendingIntent.FLAG_MUTABLE instead.
        val pendingIntent: PendingIntent =
            Intent(this, LoginActivity::class.java).let { notificationIntent ->
                PendingIntent.getActivity(this, 10, notificationIntent,
                    PendingIntent.FLAG_IMMUTABLE)
            }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
                    NotificationManager
            val channel = NotificationChannel("mqtt_service", "mqtt_service",
                NotificationManager.IMPORTANCE_MIN)
            manager.createNotificationChannel(channel)
        }
        val notification: Notification = Notification.Builder(this, "mqtt_service")
            .setContentIntent(pendingIntent)
            .build()

        //Notification ID cannot be 0. if Notification ID is 0, the Notification could be hidden
        startForeground(11, notification)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            val connectivityManager =
                getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            connectivityManager.registerDefaultNetworkCallback(networkCallback)
        }
        val clientIdFromIntent = intent?.getStringExtra("clientId")
        Log.d("MQTTService", clientIdFromIntent.toString())
        clientIdFromIntent?.let {
            init(it)
        }
        return super.onStartCommand(intent, flags, startId);
    }
    //发布消息 msg
    //fun publish(msg: String){
    //    val topic: String = addTopic
    //    val qos: Int = 2
    //    val retained: Boolean = false
    //    try {
    //        client?.publish(topic, msg.toByteArray(), qos, retained)
    //    } catch (e: MqttException) {
    //        e.printStackTrace()
    //    }
    //}

    private fun init(clientIdFromIntent: String) {
        clientId = clientIdFromIntent
        clientId?.let {
            userNotice = UserNotice(this)
            // 服务器地址（协议+地址+端口号）
            val uri = host;
            client = MqttAndroidClient(this, uri, it, Ack.AUTO_ACK)
            // 设置MQTT监听并且接受消息
            client?.setCallback(mqttCallback)
            conOpt =  MqttConnectOptions()
            // 清除缓存
            conOpt?.isCleanSession = false
            // 设置超时时间，单位：秒
            conOpt?.connectionTimeout = 10
            // 心跳包发送间隔，单位：秒
            conOpt?.keepAliveInterval = 20
            // 用户名
            conOpt?.userName = userName
            // 密码
            conOpt?.password = passWord.toCharArray()
            // last will message
            var doConnect = true
            val message = "{\"terminal_uid\":\"$clientId\"}"

            val qos = 2
            val retained = false

            // 最后
            try {
                conOpt?.setWill("will", message.toByteArray(), qos, retained)
            } catch (e: Exception) {
                Log.i("MQTTService", "Exception Occurred", e)
                doConnect = false
                //iMqttActionListener.onFailure(null, e)
            }

            if (doConnect) {
                doClientConnection()
            }
        }

    }

    override fun onDestroy() {
        try {
            client?.disconnect()  //服务销毁,断开连接
        } catch (e: Exception) {
            e.printStackTrace()
        }
        stopForeground(true)
        super.onDestroy()
    }

    /** 连接MQTT服务器 */
    private fun doClientConnection() {
        if (client?.isConnected != true && isConnectIsNomarl()) {
            try {
                conOpt?.let {
                    client?.connect(it, null, iMqttActionListener)
                }
            } catch ( e: MqttException) {
                e.printStackTrace()
            }
        }

    }

    // MQTT是否连接成功
    private val iMqttActionListener = object : IMqttActionListener {
        override fun onSuccess( token: IMqttToken) {
            Log.i("MQTTService", "连接成功 ");
            try {
                // 订阅addTopic话题,当订阅多条频道,需要遍历逐条订阅,否则有可能订阅失败
                // 默认为 exam_task_default; 每个不同的用户exam_add_${id} exam_cancel_${id}
                Log.d("MQTTService", addTopic + clientId)
                Log.d("MQTTService", cancelTopic + clientId)
                client?.subscribe(addTopic + clientId, 1)
                client?.subscribe(cancelTopic + clientId,  1)
            } catch ( e:MqttException) {
                e.printStackTrace()
            }
        }

        override fun onFailure(arg0: IMqttToken , e: Throwable ) {
            e.printStackTrace();
            // 连接失败，重连
            if (count < 3) {
                count++
                doClientConnection()
            }
        }
    }

    // MQTT监听并且接受消息
    private val  mqttCallback =  object : MqttCallback {
        override fun messageArrived( topic: String,  message: MqttMessage) {
            Log.d("MQTTService", topic)
            val msg =  String(message.payload)
            //订阅信息,接收的信息message
            Log.i("MQTTService", "messageArrived:$msg")
            val addTopicClient = addTopic + clientId
            val cancelTopicClient = cancelTopic + clientId
            val examTask = gson.fromJson(msg, ExamTask::class.java)
            if (topic == addTopicClient) {
                //接受消息 解析消息给出用户提示 设置闹钟
                Log.d("MQTTService", examTask.toString())
                Log.d("MQTTService", userNotice.toString())
                userNotice?.setExamTaskNotification("你被分配了一场新的监考任务 点击查看详情")
                userNotice?.setAlarm(examTask)
            }
            if (topic == cancelTopicClient) {
                userNotice?.setExamTaskNotification("您有一项监考任务被取消了，点击查看详情")
                userNotice?.dismissAlarm(examTask)
            }
        }

        override fun deliveryComplete(token: IMqttDeliveryToken?) {
            Log.i("MQTTService", "发送成功");
        }

        override fun connectionLost( arg0: Throwable?) {
            // 失去连接，重连
            Log.i("MQTTService", "失去连接")
        }
    }

    /** 判断网络是否连接 */
    private fun isConnectIsNomarl(): Boolean {
        val connectivityManager = this.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val info: NetworkInfo? = connectivityManager.getActiveNetworkInfo()
        if (info != null && info.isAvailable()) {
            val name = info.getTypeName();
            Log.i("MQTTService", "MQTT当前网络名称：$name")
            return true
        } else {
            Log.i("MQTTService", "MQTT 没有可用网络")
            return false
        }
    }

    override fun onBind( intent: Intent): IBinder? {
        return null
    }

    companion object {
        fun startService(context: Context, clientId: String) {
            val intent = Intent(context, MQTTService::class.java)
            intent.putExtra("clientId", clientId)
            context.startService(intent)
        }
    }
}
